package cn.easyutil.util.javaUtil;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Authenticator;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import cn.easyutil.util.javaUtil.annotation.EmailCallBack;
import com.sun.mail.pop3.POP3Message;

/**
 * 邮件发送
 * 
 * @author spc
 *
 */
public class EmailUtil {
	//发件人用户名
	private String username;
	//发件人邮箱设置SMTP服务器,比如:smtp.163.com
	private String host;
	//发件人邮箱端口号
	private String port;
	//发件人密码
	private String password;
	//邮件内容编码 默认iso-8859-1
	private String charset = "gbk";
	//端口号
	private int portNo;
	
	public EmailUtil(String username,String password){
		this.username = username;
		this.password = password;
		Map<String, String> map = getPort(username);
		this.port = map.get("port");
		this.host = map.get("host");
	}
	public EmailUtil(String username,String password,String host,String port){
		this.username = username;
		this.password = password;
		this.host = host;
		this.port = port;
	}
	
	public int getPortNo() {
		if(this.port.equals("pop3")){
			setPortNo(995);
		}
		return portNo;
	}

	public void setPortNo(int portNo) {
		this.portNo = portNo;
	}


	public String getCharset() {
		return charset;
	}

	public void setCharset(String charset) {
		this.charset = charset;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getHost() {
		if(this.host == null){
			throw new NullPointerException("the field [host] must not be null ,please set the [SMTP] server host,example:smtp.163.com");
		}
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public String getPort() {
		if(this.port == null){
			throw new NullPointerException("the field [port] must not be null,please set the [SMTP] server port,example:stand by SSL = 465,QQ = 587,default = 25");
		}
		return port;
	}

	public void setPort(String port) {
		this.port = port;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	/**
	 * 发送邮件
	 * @param username	发送者账号
	 * @param password	发送者密码
	 * @param title	邮件标题
	 * @param text	邮件内容,可以html
	 * @param sendTo	收件人,可以多个
	 */
	public static void sendEmail(String username, String password, String title, String text, String... sendTo) {
		send(new EmailUtil(username, password), new File[]{}, title, text, sendTo);
	}

	/**
	 * 发送邮件
	 * @param username	发送者账号
	 * @param password	发送者密码
	 * @param title	邮件标题
	 * @param text	邮件内容,可以html
	 * @param sendTo	收件人,可以多个
	 */
	public static void sendEmail(String username, String password, String title, String text, File[] file,
			String... sendTo) {
		send(new EmailUtil(username, password), file, title, text, sendTo);
	}

	/**
	 * 发送邮件
	 * @param ea	发送者属性
	 * @param title	邮件标题
	 * @param text	邮件内容,可以html
	 * @param sendTo	收件人,可以多个
	 */
	public static void sendEmail(EmailUtil ea, String title, String text, File[] file,
			String... sendTo) {
		send(ea, file, title, text, sendTo);
	}
	
	/**
	 * 发送邮件
	 * @param ea	发送者属性
	 * @param title	邮件标题
	 * @param text	邮件内容,可以html
	 * @param sendTo	收件人,可以多个
	 */
	public static void sendEmail(EmailUtil ea, String title, String text,String... sendTo) {
		send(ea, new File[]{}, title, text, sendTo);
	}
	
	/**
	 * 发送邮件
	 * @param ea	发送者属性
	 * @param files	邮件附件
	 * @param title	邮件标题
	 * @param text	邮件内容,可以html
	 * @param sendTo	收件人,可以多个
	 */
	private static void send(EmailUtil ea,File[] files,String title,String text,String[] sendTo){
		Properties properties = new Properties(); 
	    properties.setProperty("mail.smtp.auth", "true");//服务器需要认证 
	    properties.setProperty("mail.transport.protocol", ea.getPort());// 声明发送邮件使用的端口 
	    properties.setProperty("mail.host", ea.getHost());// 发送邮件的服务器地址
		properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
		properties.setProperty("mail.smtp.socketFactory.port", "465");
		properties.setProperty("mail.smtp.port", "465");
	      
	    Session session = Session.getInstance(properties, new Authenticator() { 
	      String sendUserName = ea.getUsername();
//	      String sendPassword = "bferpqfqfjgibcfe";
	      String sendPassword=ea.getPassword();
	      protected PasswordAuthentication getPasswordAuthentication() {
	        return new PasswordAuthentication(sendUserName,
	            sendPassword); 
	      } 
	    }); 
	    session.setDebug(true); 
	    MimeMessage msg = new MimeMessage(session);// 声明一个邮件体
	    MimeMultipart msgMultipart = new MimeMultipart("mixed");// 标明邮件的组合关系，混合的关系
	    for(int i=0;i<files.length;i++){
	    	MimeBodyPart attch1 = new MimeBodyPart();// 附件1 
	    	// 指定附件 
	    	// 设置第一个附件 
	    	String path = files[i].getAbsolutePath();
	    	DataSource ds1 = new FileDataSource(path);// 指定附件的数据源 
	    	DataHandler dh1 = new DataHandler(ds1);// 附件的信息 
	    	try {
	    		attch1.setDataHandler(dh1);
	    		attch1.setFileName(path.substring(path.lastIndexOf(File.separator), path.length()));
				msgMultipart.addBodyPart(attch1);
			} catch (Exception e) {
				e.printStackTrace();
			} 
	    }
	    MimeBodyPart content = new MimeBodyPart();// 邮件的正文，混合体（图片+文字） 
	    try {
			msg.setFrom(ea.getUsername());
			msg.setSubject(title);//设置邮件主题 
			InternetAddress[] ins = new InternetAddress[sendTo.length];
			for (int i = 0; i < ins.length; i++) {
				InternetAddress in = new InternetAddress(sendTo[i]);
				ins[i] = in;
			}
			msg.setRecipients(MimeMessage.RecipientType.TO,ins);
			msg.setContent(msgMultipart);// 设置邮件体 
			// 将附件和正文设置到这个邮件体中 
			msgMultipart.addBodyPart(content);
		} catch (MessagingException e) {
			LoggerUtil.error(EmailUtil.class, "user of ["+ea.getUsername()+"] send email failed",e);
			throw new RuntimeException(e);
		} 
	  
	    //设置邮件的正文 
	    MimeMultipart bodyMultipart = new MimeMultipart("related");//依赖关系 
	    MimeBodyPart htmlPart = new MimeBodyPart(); 
	    try {
	    	//指定正文 
			content.setContent(bodyMultipart);
			bodyMultipart.addBodyPart(htmlPart);
			htmlPart.setContent(text, "text/html;charset="+ea.getCharset());//设置正文文字 
			msg.saveChanges();//保存邮件 
		} catch (MessagingException e) {
			LoggerUtil.error(EmailUtil.class, "user of ["+ea.getUsername()+"] send email failed",e);
			throw new RuntimeException(e);
		}
	    //将邮件保存成文件 
		try {
			Transport.send(msg);
			LoggerUtil.debug(EmailUtil.class, "user of ["+ea.getUsername()+" send email to ["+JsonUtil.beanToJson(sendTo)+"] success");
		} catch (Exception e) {
			LoggerUtil.error(EmailUtil.class, "user of ["+ea.getUsername()+"] send email failed",e);
			throw new RuntimeException(e);
		}
	  } 
	/**
	 * 根据邮箱名来确定邮箱类型
	 * 
	 * @param username
	 * @return
	 */
	private static Map<String, String> getPort(String username) {
		if (username == null || !username.contains("@")) {
			throw new RuntimeException("the email flag @ not found with the username ["+username+"],please use the mothed of sendEmail(EasyEmailUtil ea, String title, String text, File[] file,String... sendTo)");
		}
		Map<String, String> result = new HashMap<String, String>();
		// 设置SMTP服务器,比如:smtp.163.com
		// SSL enabled SMTP server,即如果是支持SSL服务器的端口是465
		// simpleEmail.setSmtpPort(465);//gmail邮箱服务器就是支持SSL的。
		if (username.endsWith("@qq.com")) {
			result.put("host", "smtp.qq.com");
			// 默认是25端口
			result.put("port", 587 + "");
		} else {
			String host = username.substring(username.indexOf("@") + 1);
			result.put("host", "smtp." + host);
			// 默认是25端口
			result.put("port", 25 + "");
		}
		return result;
	}
	/**
	 * 读取邮件
	 * @param username	发送者账号
	 * @param password	发送者密码
	 * @return
	 */
	public static EmailMessage readEmail(String username,String password){
		return readEmail(username, password, -1,null).get(0);
	}
	/**
	 * 读取邮件
	 * @param username	发送者账号
	 * @param password	发送者密码
	 * @param call	回调函数,自定义处理邮件对象
	 * @return
	 */
	public static EmailMessage readEmail(String username, String password, EmailCallBack call){
		return readEmail(username, password, -1,call).get(0);
	}
	/**
	 * 读取邮件
	 * @param username	发送者账号
	 * @param password	发送者密码
	 * @param length	获取倒数多少条
	 * @param call	回调函数,自定义处理邮件对象
	 * @return
	 */
	public static List<EmailMessage> readEmail(String username,String password,int length,EmailCallBack call){
		if(!username.contains("@")){
			throw new RuntimeException("the email flag @ not found with the username ["+username+"],please use the mothed of readEmail(EasyEmailUtil ea,int start,int end,EmailCallBack call)");
		}
		String str = username.substring(username.indexOf("@")+1);
		str = str.substring(0, str.indexOf("."));
		EmailUtil ea = new EmailUtil(username,password,"pop."+str+".com","pop3");
		return readEmail(ea,-1,length,call);
	}
	/**
	 * 读取邮件
	 * @param ea	邮箱属性
	 * @param start	开始的条数
	 * @param end	结束的条数
	 * @param call	回调函数,自定义处理邮件对象
	 * @return
	 */
	public static List<EmailMessage> readEmail(EmailUtil ea,int start,int end,EmailCallBack call){
		String protocol = ea.getPort();
	    String host = ea.getHost();
	    int port = ea.getPortNo();
	    String username = ea.getUsername();
	    String password = ea.getPassword();
	 
	    Properties props = new Properties();
	    props.put("mail."+ea.getPort()+".ssl.enable", true);
	    props.put("mail."+ea.getPort()+".host", host);
	    props.put("mail."+ea.getPort()+".port", port);
	 
	    Session session = Session.getDefaultInstance(props);
	    Store store = null;
	    Folder folder = null;
	    List<EmailMessage> result = new ArrayList<EmailUtil.EmailMessage>();
	    try {
	      store = session.getStore(protocol);
	      store.connect(username, password);
	      folder = store.getFolder("INBOX");
	      folder.open(Folder.READ_ONLY);
	      int size = folder.getMessageCount();
	      if(start<0){
	    	  start = ((size-end+1)<0||(size-end+1)>size)?size:size-end+1;
	    	  end = size;
	      }
	      if(end>size || end<start){
	    	  end = size;
	      }
	      if(end<=1){
	    	  start = size;
	    	  end = size;
	      }
	      Message[] messages = folder.getMessages(start, end);
	      for (int i = 0; i < messages.length; i++) {
	    	  EmailMessage mess = new EmailMessage();
	    	  Message message = messages[i];
	    	  String from = message.getFrom()[0].toString();
	    	  String subject = message.getSubject();
	    	  Date date = message.getSentDate();
	    	  mess.setFrom(from);
	    	  mess.setReciveTime(date);
	    	  mess.setTitle(subject);
	    	  mess.setContent(message.getContent().toString());
	    	  result.add(mess);
	    	  if(call!=null){
	    		  call.call(message);
	    	  }
	      }
	      return result;
	    } catch (Exception e) {
	    	LoggerUtil.error(EmailUtil.class, "user of ["+ea.getUsername()+"] read email failed",e);
			throw new RuntimeException(e);
	    } finally {
	      try {
	        if (folder != null) {
	          folder.close(false);
	        }
	        if (store != null) {
	          store.close();
	        }
	      } catch (MessagingException e) {
	    	  throw new RuntimeException(e);
	      }
	    }
	}
	
	/**
	 * 邮件读取后的摘要
	 * @author spc
	 *
	 */
	static class EmailMessage{
		private String from;
		private String title;
		private Date reciveTime;
		private String content;
		
		public String getFrom(){
			return from;
		}
		public void setFrom(String from) {
			this.from = from;
		}
		public String getTitle() {
			return title;
		}
		public void setTitle(String title) {
			this.title = title;
		}
		public Date getReciveTime() {
			return reciveTime;
		}
		public void setReciveTime(Date reciveTime) {
			this.reciveTime = reciveTime;
		}

		public String getContent() {
			return content;
		}

		public void setContent(String content) {
			this.content = content;
		}
	}
	
	public static void main(String[] args) {
		EmailCallBack callBack = new EmailCallBack(){
			@Override
			public void call(Message message) {
				try {
					Object content = message.getContent();
//					byte[] bytes = message.getContent().toString().getBytes();
					InputStream inputStream = ((POP3Message) message).getMimeStream();
					byte[] bytes = IOUtil.inputToByte(inputStream);
					FileOutputStream out = new FileOutputStream(new File("D://email.html"));
					out.write(bytes);
					out.flush();
				} catch (IOException e) {
					e.printStackTrace();
				} catch (MessagingException e) {
					e.printStackTrace();
				}
			}
		};
		EmailMessage message = EmailUtil.readEmail("547595531@qq.com", "wnzxmgthwjskbfeb",callBack);
		System.out.println(message);
	}
}
